﻿// Implement the "Falling Rocks" game in the text console. 

using System;
using System.Threading;
using System.Collections.Generic;

class Dwarf
{
    private int coordX;
    private int coordY;

    private int limitX;

    private string dwarfSymbol;
    private string emptyDwarf;

    public int Position
    {
        get { return coordX; }
    }

    public int Length
    {
        get { return dwarfSymbol.Length; }
    }

    public Dwarf(string symbol, int startX, int positionY, int screenSize)
    {
        dwarfSymbol = symbol;
        emptyDwarf = new string(' ', dwarfSymbol.Length);

        coordX = startX;
        coordY = positionY;

        limitX = screenSize - dwarfSymbol.Length - 1;
    }

    public void Render()
    {
        Console.SetCursorPosition(coordX, coordY);
        Console.ForegroundColor = ConsoleColor.White;
        Console.Write(dwarfSymbol);
    }

    public void MoveLeft()
    {
        if (coordX > 1)
        {
            //clear the old position
            Console.SetCursorPosition(coordX, coordY);
            Console.Write(emptyDwarf);

            coordX--;
            this.Render();
        }
    }

    public void MoveRight()
    {
        if (coordX < limitX)
        {
            //clear the old position
            Console.SetCursorPosition(coordX, coordY);
            Console.Write(emptyDwarf);

            coordX++;
            this.Render();
        }
    }
}

class Rock
{
    private static readonly Random rnd = new Random();

    private int position;
    private int currentY;
    private string symbols;
    private ConsoleColor rockColor;

    public int CurrentY
    {
        get { return this.currentY; }
    }

    public int Position
    {
        get { return this.position; }
    }

    public int Length
    {
        get { return this.symbols.Length; }
    }

    public Rock(int startY)
    {
        this.currentY = startY;

        int randomCount = rnd.Next(0, 10);
        int countOfChars = 0;

        if (randomCount < 5)
        {
            countOfChars = 1;
        }
        else if ((randomCount >= 6) && (randomCount <= 8))
        {
            countOfChars = 2;
        }
        else
        {
            countOfChars = 3;
        }

        char[] allowedSymbols = { '^', '@', '*', '&', '+', '%', '$', '#', '!', '.', ';' };
        this.symbols = new string(allowedSymbols[rnd.Next(allowedSymbols.Length)], countOfChars);
       
        this.position = rnd.Next(49 - this.symbols.Length);

        rockColor = (ConsoleColor)rnd.Next(1, 16);
    }

    public void Render()
    {
        Console.SetCursorPosition(this.position, this.currentY);
        Console.ForegroundColor = this.rockColor;
        Console.Write(this.symbols);
    }

    public void Next()
    {
        //Clear old place
        Console.SetCursorPosition(this.position, this.currentY);
        Console.Write(new string(' ', this.symbols.Length));
        this.currentY++;
    }
}

class Rocks
{
    private static readonly Random rnd = new Random();

    private List<Rock> rocks;
    private int numberOfLines;
    private int startLine;

    private void GenerateNextLine()
    {
        int numberRocks = rnd.Next(3);
        for (int i = 0; i <= numberRocks; i++)
		{
            Rock rockToAdd = new Rock(1);
            rocks.Add(rockToAdd);
		}
    }

    public Rocks(int numberOflines, int startLine)
    {
        this.numberOfLines = numberOflines;
        this.startLine = startLine;

        rocks = new List<Rock>(this.numberOfLines * 4);
        
        GenerateNextLine();
    }

    public void Render()
    {
        foreach (Rock rockToDraw in rocks)
        {
            rockToDraw.Render();
        }
    }

    public bool Next(Dwarf dwarf)
    {
        foreach (Rock rockToUpdate in rocks)
        {
            rockToUpdate.Next();
        }
        GenerateNextLine();

        int rocksToDelete = 0;
        for (int i = 0; i < rocks.Count; i++) 
        {
            if (rocks[i].CurrentY == numberOfLines)
            {
                bool gameOver = (rocks[i].Position >= dwarf.Position) && (rocks[i].Position < dwarf.Position + dwarf.Length);
                gameOver |= (rocks[i].Position < dwarf.Position) && (rocks[i].Position + rocks[i].Length - 1 >= dwarf.Position);
                if (gameOver)
                {
                    return true;
                }
            }

            if (rocks[i].CurrentY > numberOfLines)
            {
                rocksToDelete = i + 1;
            }
        }
        if (rocksToDelete != 0)
        {
            rocks.RemoveRange(0, rocksToDelete);
        }

        return false;
    }
}

class GameFallingRocks
{
    private const int ScreenSizeX = 51;
    private const int ScreenSizeY = 31;

    static void RenderScore(uint score)
    {
        Console.SetCursorPosition(20, 0);
        Console.ForegroundColor = ConsoleColor.White;
        Console.Write("Score:{0}", score);
    }

    static void GameOver(uint score)
    {
        Console.Clear();

        Console.ForegroundColor = ConsoleColor.Red;
        Console.SetCursorPosition(21, 14);
        Console.Write("GAME OVER");

        Console.SetCursorPosition(14, 15);
        Console.Write("Your score is {0} points.", score);

        Console.ForegroundColor = ConsoleColor.White;
        Console.SetCursorPosition(10, 17);
        Console.Write("Pess any key to close the game..");
        Console.ReadKey();
    }

    static void Main()
    {
        //init the Console
        Console.Clear();
        Console.BufferHeight = Console.WindowHeight = ScreenSizeY;
        Console.BufferWidth = Console.WindowWidth = ScreenSizeX;
        Console.CursorVisible = false;

        //init the dwarf
        Dwarf dwarf = new Dwarf("(0)", (ScreenSizeX) / 2 - 1, ScreenSizeY - 1, ScreenSizeX);
        dwarf.Render();

        //init the rocks
        Rocks rocks = new Rocks(ScreenSizeY - 1, 1);

        bool exit = false;
        uint ticks = 0;
        uint score = 0;

        while (!exit)
        {
            if (Console.KeyAvailable == true)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);

                if (key.Key == ConsoleKey.LeftArrow)
                {
                    dwarf.MoveLeft();
                }

                if (key.Key == ConsoleKey.RightArrow)
                {
                    dwarf.MoveRight();
                }

                if (key.Key == ConsoleKey.Escape)
                {
                    exit = true;
                }
            }
 
            RenderScore(score);

            rocks.Render();

            dwarf.Render();

            Thread.Sleep(150 - ((int)score / 50) * 25);

            //increase score every 1.05s (7*150ms)
            if (ticks == 7)
            {
                ticks = 0;
                score++;
                if (rocks.Next(dwarf))
                {
                    GameOver(score);
                    exit = true;
                }
            }
            else
            {
                ticks++;
            }
        }
    }
}